
/*
 * Copyright (c) 2020 Actions Semiconductor Co., Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief micin detect driver for Actions SoC
 */

#include <errno.h>
#include <kernel.h>
#include <string.h>
#include <init.h>
#include <adc.h>
#include <hotplug.h>
#include <misc/util.h>
#include <misc/byteorder.h>
#include <board.h>
#include <gpio.h>

#define SYS_LOG_DOMAIN "MICIN_DETECT"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_MICIN_DETECT_LEVEL
#include <logging/sys_log.h>

struct micin_detect_info {
#ifndef BOARD_MICIN_DETECT_GPIO
		struct device *adc_dev;
		struct adc_seq_table seq_tbl;
		struct adc_seq_entry seq_entrys;
		u8_t adcval[4];
#else
	struct device *dectect_gpio_dev;
#endif
};

struct micin_detect_config {
	char *adc_name;
	u16_t adc_chan;
};
#ifndef BOARD_MICIN_DETECT_GPIO
struct micin_vol_range {
	u16_t min;
	u16_t max;
};

struct micin_vol_range micin_vol = {
#ifdef MICIN_DETEC_ADVAL_RANGE
	MICIN_DETEC_ADVAL_RANGE
#endif
};
static unsigned int micin_detect_adcval_to_state(unsigned int adcval)
{
	printk("mic adcval:%d\n",adcval);
	if (adcval >= micin_vol.min && adcval <= micin_vol.max) {
		return MICIN_IN;
	} else if (adcval > micin_vol.max) {
		return MICIN_OUT;
	}
	return MICIN_NONE;
}
#endif


static int micin_detect_state(struct device *dev, int *state)
{
	struct micin_detect_info *micin_detect = dev->driver_data;
	#ifdef BOARD_MICIN_DETECT_GPIO
	int err, value;
	err = gpio_pin_read(micin_detect->dectect_gpio_dev, BOARD_MICIN_DETECT_GPIO,
			    &value);
	if (err) {
		return 0;
	}
	//printk("mic in status:%d\n",value);
	if (value == BOARD_MICIN_DETECT_GPIO_VALUE) {
		*state = MICIN_IN;
	} else {
		*state = MICIN_OUT;
	}
	
	#else
	int adc_val;

	adc_read(micin_detect->adc_dev, &micin_detect->seq_tbl);
	adc_val = sys_get_le16(micin_detect->seq_entrys.buffer);

	*state = micin_detect_adcval_to_state(adc_val);
	#endif
	return 0;
}

static const struct hotplog_detect_driver_api micin_detect_driver_api = {
	.detect_state = micin_detect_state,
};

static int micin_detect_init(struct device *dev)
{
	struct micin_detect_info *micin_detect = dev->driver_data;
	printk("line in detect init!!!\n");
	#ifdef BOARD_MICIN_DETECT_GPIO
	micin_detect->dectect_gpio_dev = device_get_binding(BOARD_MICIN_DETECT_GPIO_NAME);
	if (!micin_detect->dectect_gpio_dev) {
		SYS_LOG_ERR("device binding failed %s\n", BOARD_MICIN_DETECT_GPIO_NAME);
		return -ENODEV;
	}
	printk("GPIO init!!!\n");
	gpio_pin_configure(micin_detect->dectect_gpio_dev, BOARD_MICIN_DETECT_GPIO, GPIO_DIR_IN | GPIO_PUD_PULL_UP);
	#else
	const struct micin_detect_config *cfg = dev->config->config_info;
	SYS_LOG_DBG("linein_detect initialized\n");

	micin_detect->adc_dev = device_get_binding(cfg->adc_name);
	if (!micin_detect->adc_dev) {
		SYS_LOG_ERR("cannot found ADC device %s\n", cfg->adc_name);
		return -ENODEV;
	}

	micin_detect->seq_entrys.sampling_delay = 0;
	micin_detect->seq_entrys.buffer = (u8_t *)&micin_detect->adcval;
	micin_detect->seq_entrys.buffer_length = sizeof(micin_detect->adcval);
	micin_detect->seq_entrys.channel_id = cfg->adc_chan;

	micin_detect->seq_tbl.entries = &micin_detect->seq_entrys;
	micin_detect->seq_tbl.num_entries = 1;

	dev->driver_api = &micin_detect_driver_api;

	adc_enable(micin_detect->adc_dev);
#endif
	return 0;
}

static struct micin_detect_info micin_detect_ddata;

static const struct micin_detect_config micin_detect_cdata = {
	.adc_name = CONFIG_HOTPLUG_MICIN_DETECT_ADC_NAME,
	.adc_chan = CONFIG_HOTPLUG_MICIN_DETECT_ADC_CHAN,
};


DEVICE_AND_API_INIT(micin_detect, "micin_detect",
		    micin_detect_init,
		    &micin_detect_ddata, &micin_detect_cdata,
		    POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
		    &micin_detect_driver_api);
